/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package algorithm;

import algorithm.BlobFinder.Blob;
import database.DatabaseController;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import structure.StructureBlob;
import thread.InstanceThreadUSB;
import util.Utils;
import view.ViewCameraPanel;

/**
 *
 * @author Progresywny Maciek
 */
public class ThreadAlgorithmCount extends Thread {

    private DatabaseController databaseController;
    private ArrayList<Blob> structure;
    private Point p1;
    private Point p2;
    private int rectangleSize = 20;
    private int smallMove = 5;
    private LinkedList<Blob> fifoStructure;
    private LinkedList<Point> fifoPoint;

    public ThreadAlgorithmCount() {
        this.p1=new Point(0,0);
        this.p2=new Point(1,1);
        this.structure = new ArrayList<>();
        this.fifoStructure = new LinkedList<>();
        this.fifoPoint = new LinkedList<>();
        this.fifoStructure.add(new Blob(1, 1, 1, 1, 1, 1));
        this.fifoPoint.add(new Point(0, 0));
        this.databaseController=new DatabaseController();
    }

    
    
    public void setParameters(int rectangleSize, int smallMove){
    this.rectangleSize=rectangleSize;
    this.smallMove=smallMove;
    }
    
    private Blob fifoAddGet() {
        if (fifoStructure.size() >= 3) {
            fifoStructure.removeFirst();
        }
        fifoStructure.add(structure.get(0));

        return fifoStructure.getFirst();
    }

    private void fifoPoint(Point p) {
        if (fifoPoint.size() >= 21) {
            fifoPoint.removeFirst();
        }
        fifoPoint.add(p);
        fifoPoint.getFirst();
    }

    public void setStructure(StructureBlob structure) {
        if (structure == null) {
            this.structure = null;
        } else {
            this.structure = structure.getArrayBlobs();
        }
    }

    public void setP1(Point p1) {
        this.p1 = (Point) p1.clone();
    }

    public void setP2(Point p2) {
        this.p2 = (Point) p2.clone();
    }

    public Point getP1() {
        return p1;
    }

    public Point getP2() {
        return p2;
    }
   
    private boolean w1 = false;
    private boolean w2 = false;
    private boolean w3 = false;
    private int countFrame = 0;

    public void run() {
        while (true) {
            try {
                Thread.sleep(Utils.ftpsToMilisecond(InstanceThreadUSB.frequence));
                if (structure == null) {
                    if (countFrame > 10) {
                        w1 = false;
                        w2 = false;
                        w3 = false;
                        rectangleSize = 20;
                        countFrame = 0;
                    }
                    countFrame++;
                } else {
                    if (structure.size() == 1) {
                        countFrame = 0;
                        fifoAddGet();
                        Point move = detectMove(fifoStructure.get(1), fifoStructure.get(0));
                        fifoPoint((Point) move.clone());
                        Point absMove = (Point) new Point(Math.abs(move.x), Math.abs(move.y)).clone();
                        for (int i = 0; i < rectangleSize; i++) {
                            int j = i - Math.round(rectangleSize / 2) + rectangleSize;
                            int x = structure.get(0).xMin;
                            int y = structure.get(0).yMin;

                            if (x <= (Math.round(rectangleSize / 2))) {
                                x = Math.round(rectangleSize / 2);
                            }

                            if (y <= Math.round(rectangleSize / 2)) {
                                y = Math.round(rectangleSize / 2);
                            }

                            int det = collinearMethod(p1, p2, x + j, y + j);
                            if (det > 0 && (absMove.x > smallMove || absMove.y > smallMove)) {
                                w1 = true;
                            }
                            if (det == 0 && (absMove.x > smallMove || absMove.y > smallMove)) {
                                w2 = true;
                                rectangleSize = 1;
                            }
                            if (det < 0 && (absMove.x > smallMove || absMove.y > smallMove)) {
                                w3 = true;
                            }
                        }
                    }
                }

                if (w1 == true && w2 == true && w3 == true) {
                    int x = 0;
                    int y = 0;
                    for (Point p : fifoPoint) {
                        x = x + p.x;
                        y = y + p.y;
                    }
                    
                    if (x > 0 || y > 0) {
                        databaseController.incrementEntry(ViewCameraPanel.actualID);
                    } else {
                        databaseController.incrementExit(ViewCameraPanel.actualID);
                    }
                    
                    fifoPoint.clear();
                    w1 = false;
                    w2 = false;
                    w3 = false;
                    rectangleSize = 20;
                    structure=null;
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(ThreadAlgorithmCount.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private int collinearMethod(Point p1, Point p2, int px, int py) {
        if (p1 != null || p2 != null) {
            int i, det; //wyznacznik macierzy
            int x[] = new int[3]; //tablica wspolrzednych x punktow
            int y[] = new int[3]; //tablica wspolrzednych y punktow    
            
            x[0] = p1.x;
            x[1] = p2.x;
            x[2] = px;
            y[0] = p1.y;
            y[1] = p2.y;
            y[2] = py;
//      Oblicznie wyznacznika macierzy
            det = x[0] * y[1] + x[1] * y[2] + x[2] * y[0]
                    - x[2] * y[1] - x[0] * y[2] - x[1] * y[0];

            return det;
        } else {
            return -1;
        }
    }

    private Point detectMove(Blob b, Blob bOld) {
        Rectangle r = new Rectangle(b.xMin, b.yMin, b.xMax - b.xMin, b.yMax - b.yMin);
        Rectangle rOld = new Rectangle(bOld.xMin, bOld.yMin, bOld.xMax - bOld.xMin, bOld.yMax - bOld.yMin);
        int xNew = r.x;
        int yNew = r.y;
        int widthNew = r.width;
        int heightNew = r.height;
        int xMove = (xNew + widthNew / 2) - (rOld.x + rOld.width / 2);
        int yMove = (yNew + heightNew / 2) - (rOld.y + rOld.height / 2);
        return new Point(xMove, yMove);
    }
}
